/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package obiekty;

import java.awt.Image;
import java.util.Iterator;
import java.util.LinkedList;
import prostagra.Mapa;
import utils.Vector2D;

/**
 *Klasa abstrakcyjna użyta w reprezentacji wszystkich obiektór poruszających się po mapie
 * @author m
 */
public abstract class ObiektRuchomy
{

    Image image;
    // position (pixels)
    protected Vector2D pozycja;
    protected Vector2D predkosc;
    protected Vector2D sila;
    protected Vector2D orientacja;
    protected double masa;
    protected double maxPredkosc;
    protected double maxSila;
    protected Grupa grupa;
    protected int promien;
    protected int zycie;
    protected int maxZycie;

    public int getMaxZycie()
    {
        return maxZycie;
    }

    public void setMaxZycie(int maxZycie)
    {
        this.maxZycie = maxZycie;
    }

    public int getZycie()
    {
        return zycie;
    }

    public void setZycie(int zycie)
    {
        this.zycie = zycie<0?0:zycie;
    }
    protected Mapa mapa;

    public void hit()
    {
        setZycie(zycie-1);
    }

    public int getPromien()
    {
        return promien;
    }

    public void setPromien(int promien)
    {
        this.promien = promien;
    }

    public ObiektRuchomy(Image image)
    {
        this.image = image;
        promien = Math.max(image.getHeight(null) / 2, image.getWidth(null) / 2) + 1;
        mapa = Mapa.getInstance();
    }

    public abstract void update(long elapsedTime);
    // GETTERS & SETTERS
    public Grupa getGrupa()
    {
        return grupa;
    }

    public void setGrupa(Grupa grupa)
    {
        this.grupa = grupa;
    }

    public Vector2D getOrientacja()
    {
        return orientacja;
    }

    public void setOrientacja(Vector2D orientacja)
    {
        this.orientacja = orientacja;
    }

    public double getMaxPredkosc()
    {
        return maxPredkosc;
    }

    public void setMaxPredkosc(double maxPredkosc)
    {
        this.maxPredkosc = maxPredkosc;
    }

    public double getMaxSila()
    {
        return maxSila;
    }

    public void setMaxSila(double maxSila)
    {
        this.maxSila = maxSila;
    }

    public Vector2D getSila()
    {
        return sila;
    }

    public void setSila(Vector2D sila)
    {
        this.sila = sila;
    }

    public double getMasa()
    {
        return masa;
    }

    public void setMasa(double masa)
    {
        this.masa = masa;
    }

    public Vector2D getPozycja()
    {
        return pozycja;
    }

    public void setPozycja(Vector2D pozycja)
    {
        this.pozycja = pozycja;
    }

    public Vector2D getPredkosc()
    {
        return predkosc;
    }

    public void setPredkosc(Vector2D predkosc)
    {
        this.predkosc = predkosc;
    }

    public int getWidth()
    {
        return image.getWidth(null);
    }

    public int getHeight()
    {
        return image.getHeight(null);
    }

    public Image getImage()
    {
        return image;
    }

    /**
     * Sprawdza czy istnieje kolizja na pozycji, na którą chcemy przesunąć obiekt ruchomy
     * @param nowaPozycja pozycja, którą chcemy sprawdzić czy jest wolna
     * @return true - jeśli na nowej pozycji jest kolizja, false - jeśli na nowej pozycji nie 
     * ma kolizji
     */
    public boolean istniejaKolizje(Vector2D nowaPozycja)
    {

        // Sprawdzamy kolizję z graczem
        if (this instanceof Gracz == false)
        {
            ObiektRuchomy o = mapa.getGracz();
            Vector2D toEntity = nowaPozycja.subtract(o.getPozycja());

            double dist = toEntity.length();

            // jeżeli na nowej pozycji będziemy nachodzić na obiekt ruchomy to zwracamy, że jest kolizja
            double amountOfOverLap = this.getPromien() + o.getPromien() - dist;
            if (amountOfOverLap >= 0 && amountOfOverLap <= this.getPromien() + o.getPromien())
            {
                return true;
            }
        }


        synchronized (mapa.getObiektyRuchome())
        {
            // Sprawdzamy kolizję z potworem
            Iterator<ObiektRuchomy> i = mapa.getObiektyRuchome().iterator();
            while (i.hasNext())
            {
                ObiektRuchomy o = i.next();
                //make sure we don't check against the individual
                if (this.equals(o))
                {
                    continue;            //calculate the distance between the positions of the entities
                }
                Vector2D toEntity = nowaPozycja.subtract(o.getPozycja());

                double dist = toEntity.length();

                // jeżeli na nowej pozycji będziemy nachodzić na obiekt ruchomy to zwracamy, że jest kolizja
                double amountOfOverLap = this.getPromien() + o.getPromien() - dist;
                if (amountOfOverLap >= 0 && amountOfOverLap <= this.getPromien() + o.getPromien())
                {
                    return true;
                }
            }
        }


        synchronized (mapa.getObiektyStale())
        {
            // Sprawdzamy kolizję z obiektami
            Iterator<ObiektStaly> it = mapa.getObiektyStale().iterator();
            while (it.hasNext())
            {
                ObiektStaly o = it.next();
                Vector2D toEntity = nowaPozycja.subtract(o.getPozycja());

                double dist = toEntity.length();

                // jeżeli na nowej pozycji będziemy nachodzić na obiekt stały to zwracamy że jest kolizja
                double amountOfOverLap = this.getPromien() + o.getPromien() - dist;
                if (amountOfOverLap >= 0 && amountOfOverLap <= this.getPromien() + o.getPromien())
                {
                    return true;
                }
            }
        }

        synchronized (mapa.getMury())
        {
            //Sprawdzamy kolizję z murami
            Iterator<Mur> ite = mapa.getMury().iterator();
            while (ite.hasNext())
            {
                Mur o = ite.next();

                double a;
                double b;
                if (o.getPozycjaPoczatkowa().x - o.getPozycjaKoncowa().x == 0)
                {
                    // PIONOWY MUR
                    if (Math.abs(nowaPozycja.x - o.getPozycjaPoczatkowa().x) <= this.getPromien())
                    {
                        return true;
                    }
                } else if (o.getPozycjaPoczatkowa().y - o.getPozycjaKoncowa().y == 0)
                {
                    // POZIOMY MUR
                    if (Math.abs(nowaPozycja.y - o.getPozycjaPoczatkowa().y) <= this.getPromien())
                    {
                        return true;
                    }
                } else
                {
                    // FUNKCJA y = ax + b, gdzie a!=0 && b != 0
                    a = (o.getPozycjaPoczatkowa().y - o.getPozycjaKoncowa().y) / (o.getPozycjaPoczatkowa().x - o.getPozycjaKoncowa().x);
                    b = o.getPozycjaPoczatkowa().y - a * o.getPozycjaPoczatkowa().x;
                }
            }
        }

        return false;
    }

    /**
     * Przesuwa obiekt na nową pozycję o ile nie wystąpi kolizja
     * @param nowaPozycja Pozycja na którą chcemy przesunąć obiekt
     */
    public void przesunObiekt(Vector2D nowaPozycja)
    {
        if (istniejaKolizje(nowaPozycja) == false)
        {
            this.pozycja = nowaPozycja;
        }
    }
}
